package main

import (
	"fmt"
	"sort"
)

func main() {
	/*
		map key value 形式的结构，无序的键值对这种数据类型
		map[key] = value
		也称为集合
	*/

	// map 的定义
	// 第一步：申明
	var myMap map[string]string
	// 第二步：make
	myMap = make(map[string]string)
	myMap["Mon"] = "周一"
	myMap["Tue"] = "周二"
	myMap["Wed"] = "周三"
	myMap["Thu"] = "周四"
	myMap["Fri"] = "周五"

	fmt.Println(myMap) // map[Fri:周五 Mon:周一 Thu:周四 Tue:周二 Wed:周三]
	// 和数组一样,可以使用key来修改map中的元素
	myMap["Mon"] = "大周一"
	fmt.Println(myMap) // map[Fri:周五 Mon:大周一 Thu:周四 Tue:周二 Wed:周三]
	// 尝试获取 map 中没有的值
	fmt.Println(myMap["Sat"]) // 为空 ，不会发生任何异常或者产生警告
	// map len
	fmt.Println(len(myMap)) // 5

	// 申明 map 的时候同时赋值
	var myMap2 = map[string]string{
		"name":   "demonlb",
		"age":    "25",
		"gender": "male",
	}

	fmt.Println(myMap2) // map[age:25 gender:male name:demonlb]

	// 通过 :=
	myMap3 := make(map[string]int)
	myMap3["Mon"] = 1
	myMap3["Tue"] = 2
	myMap3["Wed"] = 3
	myMap3["Thu"] = 4
	fmt.Println(myMap3) // map[Mon:1 Thu:4 Tue:2 Wed:3]

	// 切片、函数不能作为 map 的 key
	// incomparable map key type []string
	// myMap4 := map[[]string]int{}

	// 将 slice 赋值给 map
	myMap5 := map[int][]string{}
	var mySlice []string
	mySlice = make([]string, 3)

	mySlice[0] = "demonlb"
	mySlice[1] = "25"
	mySlice[2] = "male"

	myMap5[0] = mySlice

	fmt.Println(myMap5) // map[0:[demonlb 25 male]]

	// 只申明没有 make，会报错
	// var myMap6 map[string]string
	// panic: assignment to entry in nil map
	// 即没有分配内存空间
	// myMap6["a"] = "b"
	// nil 类似于 null

	// map 是引用类型
	fmt.Println(myMap3) // map[Mon:1 Thu:4 Tue:2 Wed:3]
	changeMap(myMap3)
	fmt.Println(myMap3) // map[Mon:100 Thu:4 Tue:2 Wed:3]
	// 可以直接通过函数传递值的方式来改变值

	// 如何来对 map 的 key 进行有顺序的输出
	// 对星期进行一个 key 的排序，for range
	fmt.Println(myMap3) // map[Mon:100 Thu:4 Tue:2 Wed:3]
	// 对 key 的首字母的 ASCII 码进行排序

	var sortKeys []string
	for key := range myMap3 {
		sortKeys = append(sortKeys, key)
	}
	fmt.Printf("排序前sortKeys的值=%v\n", sortKeys)
	// 排序前sortKeys的值=[Mon Tue Wed Thu]

	// 引入 sort 排序方法
	sort.Strings(sortKeys)
	fmt.Printf("排序后sortKeys的值=%v\n", sortKeys)
	// 排序后sortKeys的值=[Mon Thu Tue Wed]

	for i := 0; i < len(sortKeys); i++ {
		fmt.Printf("myMap3[%s]=%d\n", sortKeys[i], myMap3[sortKeys[i]])
		/*
			myMap3[Mon]=100
			myMap3[Thu]=4
			myMap3[Tue]=2
			myMap3[Wed]=3
		*/
	}

	// 结构体和 c 类似
	// 定义一个结构体作为 map 的值
	type course struct {
		courseName    string  // 课程名称
		courseTime    float32 // 课程时长 单位分钟
		courseTeacher string  // 课程讲师
	}

	course1 := course{
		courseName: "英语课", courseTime: 300.1, courseTeacher: "demonlb",
	}

	course2 := course{
		courseTime: 300.2, courseTeacher: "robin", courseName: "生物课",
	}

	myCourse := make(map[string]course)
	myCourse["English"] = course1
	myCourse["Biology"] = course2

	fmt.Println(myCourse) // map[Biology:{生物课 300 robin} English:{英语课 300 demonlb}]
	// 打印出了 myCourse 的类型 是一个 map，并且里面有两个值，为 Biology 和 English，其中具体的值为一个我们定义的 course 结构体

	value, ok := myCourse["English"]
	// 判断是否有 "English" 这个值
	if ok {
		fmt.Println(value) // {英语课 300.1 demonlb}
	} else {
		fmt.Println("no value")
	}

	// 上面更简便的写法：
	if value, ok := myCourse["English"]; ok {
		fmt.Println(value) // {英语课 300.1 demonlb}
	}

	// map 切片 map + 切片的组合
	// interface{} 可以把他看做一个万能的类型，可以复制多种类型
	var mapSlice []map[string]interface{}
	// 这里定义了 2 个长度的 map 切片
	mapSlice = make([]map[string]interface{}, 2)
	mapSlice[0] = make(map[string]interface{}, 2)
	mapSlice[0]["name"] = "demonlb"
	mapSlice[0]["age"] = 25

	mapSlice[1] = make(map[string]interface{}, 2)
	mapSlice[1]["name"] = "robin"
	mapSlice[1]["age"] = 18

	fmt.Println(mapSlice) // [map[age:25 name:demonlb] map[age:18 name:robin]]
	// 这种数据格式用于管理大量数据，接口里会处理这里的数据
}

func changeMap(myMap map[string]int) {
	myMap["Mon"] = 100
}
